package com.mgy.mock.proxy;

import com.mgy.mock.AbstractFileReadWrite;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public class ProxyGrabAliItemService {


    private static final List<CookieInfo> cookieList = new ArrayList<>();


    static {
        String[] cookieArr = {
                  "cna=3lHrHMLDl2MCAbeGbtIWQ+sn",
//                "cna=fllXH98sWnoCAbeGbtKvrBBa;",
//                "cna=lKBVH88ihC0CAbeGbtIJmX16;",
//                "cna=c6RVH+hE/2ICAbeGbtLGAM2C;",
//                "cna=j6FVH13MvXYCAbeGbtJ4COk9;",
//                "cna=5MXmG4E9iCYCAXygOA4eyenH;",
//                "cna=GKJVH8qjlwMCAbeGbtLDzKM0;",
//                "cna=tl1vHS/ATTUCAXPsNdPWShWO;",
//                "cna=97JVHyluezMCAXPsNdIUTE8m;",
//                "cna=G7NVH1TYZmkCAXPsNdKfB94U;",
//                "cna=53z6FFjVjzoCAbeGbtL8RAOG;",
//                "cna=rnU7H7PSllECAXPsNdPTD63X;",
//                "cna=GtxVHxv+0CYCAbeGbtLzrVHG;",
//                "cna=SNxVH6oQZHgCAbeGbtJobpf/;",
//                "cna=cdxVH8+C1XACAbeGbtKVBn+L;",
//                "cna=m9xVH2T4v3ECAbeGbtIxBek5;",
//                "cna=6NxVH5p29AICAbeGbtLrwuxO;",
//                "cna=3lHrHMLDl2MCAbeGbtIWQ;",
//                "cna=Zd1VH08XgkICAbeGbtKAGaar;",
//                "cna=jd1VH4L/XzUCAbeGbtJqVrJR;",
//                "cna=z91VH5S4wHMCAbeGbtJxM6E4;",
//                "cna=L95VH27XQBACAXPsNdJ7KOks;",
//                "cna=Z/dVH+CyPCkCAbeGbtIM/Xxt;",
//                "cna=LbFUHzaC3VICAbeGbtIDE53Y;"
        };

        for (String cookie : cookieArr) {
            CookieInfo cookieInfo = new CookieInfo();
            cookieInfo.setLastUseTime(null);
            cookieInfo.setLastBanTime(null);
            cookieInfo.setCookie(cookie);
            String[] arr = cookie.split("; ");
            for (String s : arr) {
                if (StringUtils.isNotBlank(s)) {
                    String[] kv = s.split("=");
                    cookieInfo.getCookieMap().put(kv[0], kv[1]);
                }
            }
            cookieList.add(cookieInfo);
        }
    }


    public String getUA() {
        String[] ua = {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
                "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36 OPR/37.0.2178.32",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586",
                "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko",
                "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)",
                "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)",
                "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0)",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 BIDUBrowser/8.3 Safari/537.36",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36 Core/1.47.277.400 QQBrowser/9.4.7658.400",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 UBrowser/5.6.12150.8 Safari/537.36",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36 SE 2.X MetaSr 1.0",
                "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36 TheWorld 7",
                "Mozilla/5.0 (Windows NT 6.1; W…) Gecko/20100101 Firefox/60.0"};

        int index = new Random().nextInt(ua.length);
        return ua[index];
    }

    public Map<String, String> getCommonHeaders() {
        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("user-agent", getUA());
        headerMap.put("sec-ch-ua", "\"Chromium\";v=\"128\", \"Not;A=Brand\";v=\"24\", \"Google Chrome\";v=\"128\"");
        headerMap.put("sec-ch-ua-platform", "\"macOS\"");
        headerMap.put("sec-fetch-dest", "document");
        headerMap.put("sec-fetch-site", "same-site");
        headerMap.put("sec-fetch-mode", "navigate");
        headerMap.put("sec-fetch-user", "?1");
        headerMap.put("upgrade-insecure-requests", "1");
        headerMap.put("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
        headerMap.put("accept-language", "zh-CN,zh;q=0.9");
        headerMap.put("cache-control", "max-age=0");
        headerMap.put("priority", "u=0, i");
        headerMap.put("referer", "https://www.1688.com/");

        // 设置IP切换头
        String proxyHeadKey = "Proxy-Tunnel";
        // 设置Proxy-Tunnel
        Random random = new Random();
        int tunnel = random.nextInt(10000);
        String proxyHeadVal = String.valueOf(tunnel);
        headerMap.put(proxyHeadKey, proxyHeadVal);

        return headerMap;
    }


    public CookieInfo getCookies() {
        synchronized (cookieList) {
            List<CookieInfo> cookieInfos = cookieList.stream().filter(c -> c.getLastUseTime() == null).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(cookieInfos)) {
                CookieInfo cookieInfo = cookieInfos.get(0);
                cookieInfo.setLastUseTime(LocalDateTime.now());
                return cookieInfo;
            }
            cookieInfos = cookieList.stream().filter(c -> c.getLastBanTime() == null).sorted(Comparator.comparing(CookieInfo::getLastUseTime)).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(cookieInfos)) {
                CookieInfo cookieInfo = cookieInfos.get(0);
                cookieInfo.setLastUseTime(LocalDateTime.now());
                return cookieInfo;
            }

            //如果所以cookie都被绊过，则取使用时间最早的一个
            cookieInfos = cookieList.stream().sorted(Comparator.comparing(CookieInfo::getLastUseTime)).collect(Collectors.toList());
            CookieInfo cookieInfo = cookieInfos.get(0);
            if (cookieInfo.getLastUseTime().plusSeconds(10).isAfter(LocalDateTime.now())) {
                //需要等待
                return null;
            }
            cookieInfo.setLastUseTime(LocalDateTime.now());
            return cookieInfo;
        }
    }


    //非代理
    public Integer request(String targetDomain, String path, Map<String, String> headerMap, Map<String, String> cookieMap, Consumer<String> consumer) throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {

        // 设置要访问的HttpHost,即是目标站点的HttpHost
        HttpHost target = new HttpHost(targetDomain, 443, "https");
        try (CloseableHttpClient httpClient = HttpClients.custom().build()) {
            RequestConfig config = RequestConfig.custom().build();

            HttpGet httpGet = new HttpGet(path);
            httpGet.setConfig(config);
            if (headerMap != null && headerMap.size() > 0) {
                headerMap.forEach(httpGet::setHeader);
            }
            // 创建一个Cookie存储对象
            CookieStore cookieStore = new BasicCookieStore();
            // 创建一个HttpClientContext对象，并将Cookie存储设置进去
            HttpClientContext context = HttpClientContext.create();
            context.setCookieStore(cookieStore);
            if (cookieMap != null && cookieMap.size() > 0) {
                List<String> list = new ArrayList<>();
                cookieMap.forEach((k, v) -> {
                    // 设置cookie
                    cookieStore.addCookie(new BasicClientCookie(k, v));
                    list.add(k + "=" + v);
                });
                httpGet.setHeader("cookie", StringUtils.join(list, ";"));
            }


            CloseableHttpResponse response = httpClient.execute(target, httpGet, context);
            HttpEntity entry = response.getEntity();
            String content = new String(EntityUtils.toByteArray(entry), StandardCharsets.UTF_8);
            consumer.accept(content);
            return response.getStatusLine().getStatusCode();
        } catch (Exception e) {
            e.printStackTrace();
            return -100;
        }
    }


    //设置代理
    public Integer proxyRequest(ProxyServer proxyServer, String targetDomain, String path, Map<String, String> headerMap, Map<String, String> cookieMap, Consumer<String> consumer) throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        String proxyHost = proxyServer.getProxyHost();
        int proxyPort = proxyServer.getProxyPort();
        String proxyUser = proxyServer.getProxyUser();
        String proxyPassword = proxyServer.getProxyPassword();

        // 设置要访问的HttpHost,即是目标站点的HttpHost
        HttpHost target = new HttpHost(targetDomain, 443, "https");
        // 设置代理HttpHost
        HttpHost proxy = new HttpHost(proxyHost, proxyPort, "http");
        // 创建CredentialsProvider对象，用于存储认证信息
        CredentialsProvider credsProvider = new BasicCredentialsProvider();

        // 以及代理的用户名和密码
        credsProvider.setCredentials(
                new AuthScope(proxy),
                new UsernamePasswordCredentials(proxyUser, proxyPassword));


        // 创建SSL/TLS环境
        SSLContextBuilder builder = new SSLContextBuilder();
        builder.loadTrustMaterial(null, (chain, authType) -> true); // 信任所有证书
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(builder.build());

        // 配置连接管理器
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(20); // 最大连接数
        cm.setDefaultMaxPerRoute(10); // 每个路由的默认最大连接数


        try (CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).setConnectionManager(cm)
                .setDefaultCredentialsProvider(credsProvider).build()) {
            RequestConfig config = RequestConfig.custom().setProxy(proxy).build();

            HttpGet httpGet = new HttpGet(path);
            httpGet.setConfig(config);
            if (headerMap != null && headerMap.size() > 0) {
                headerMap.forEach(httpGet::setHeader);
            }
            // 创建一个Cookie存储对象
            CookieStore cookieStore = new BasicCookieStore();
            // 创建一个HttpClientContext对象，并将Cookie存储设置进去
            HttpClientContext context = HttpClientContext.create();
            context.setCookieStore(cookieStore);
            if (cookieMap != null && cookieMap.size() > 0) {
                List<String> list = new ArrayList<>();
                cookieMap.forEach((k, v) -> {
                    // 设置cookie
                    cookieStore.addCookie(new BasicClientCookie(k, v));
                    list.add(k + "=" + v);
                });
                httpGet.setHeader("cookie", StringUtils.join(list, ";"));
            }


            CloseableHttpResponse response = httpClient.execute(target, httpGet, context);
            HttpEntity entry = response.getEntity();
            String content = new String(EntityUtils.toByteArray(entry), StandardCharsets.UTF_8);
            consumer.accept(content);
            return response.getStatusLine().getStatusCode();
        } catch (Exception e) {
            e.printStackTrace();
            return -100;
        }
    }


    public GrabResult proxyGet1688Item(String targetDomain, String path, CookieInfo cookieInfo) throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, InterruptedException {
        GrabResult grabResult = new GrabResult();
        ProxyServer proxyServer = ProxyServerFactory.getProxyServer();
        Map<String, String> headerMap = getCommonHeaders();
        if (cookieInfo == null) {
            TimeUnit.SECONDS.sleep(20);
            grabResult.setSuccess(false);
            grabResult.setMessage("没有可用的cookie");
            return grabResult;
        }
        Integer statusCode = proxyRequest(proxyServer, targetDomain, path, headerMap, cookieInfo.getCookieMap(), content -> {
            grabResult.setThreadId(Thread.currentThread().getId());
            if (content != null && content.contains("window.data.offerresultData")) {
                grabResult.setMessage("抓取成功！");
            } else {
                grabResult.setSuccess(false);
                grabResult.setMessage("抓取失败！");
            }
        });
        grabResult.setStatusCode(statusCode);
        return grabResult;
    }


    public GrabResult get1688Item(String targetDomain, String path, CookieInfo cookieInfo) throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, InterruptedException {
        GrabResult grabResult = new GrabResult();
        Map<String, String> headerMap = getCommonHeaders();
        if (cookieInfo == null) {
            TimeUnit.SECONDS.sleep(20);
            grabResult.setSuccess(false);
            grabResult.setMessage("没有可用的cookie");
            return grabResult;
        }
        Integer statusCode = request(targetDomain, path, headerMap, cookieInfo.getCookieMap(), content -> {
            grabResult.setThreadId(Thread.currentThread().getId());
            if (content != null && content.contains("window.data.offerresultData")) {
                grabResult.setMessage("抓取成功！");
            } else {
                grabResult.setSuccess(false);
                grabResult.setMessage("抓取失败！");
            }
        });
        grabResult.setStatusCode(statusCode);
        return grabResult;
    }
}
